package com.zshan.clinic.web.listener;

import com.zshan.clinic.admin.constant.RedisKeyPrefix;
import com.zshan.clinic.admin.service.medical.ClinicMedicalService;
import com.zshan.clinic.admin.service.medical.ClinicQueueService;
import com.zshan.clinic.admin.service.medical.ClinicRegisterService;
import com.zshan.clinic.common.constant.CommonConstant;
import com.zshan.clinic.common.util.lock.RedissonLockUtil;
import com.zshan.clinic.database.model.ClinicRegister;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.Message;
import org.springframework.data.redis.listener.KeyExpirationEventMessageListener;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;


/**
 * 监听redis失效的key来实现延迟任务
 */
@Component
@Slf4j
public class RedisKeyExpiredListener extends KeyExpirationEventMessageListener {

    @Autowired
    private ClinicQueueService checkinService;

    @Autowired
    private ClinicMedicalService clinicMedicalService;

    @Autowired
    private ClinicRegisterService registerService;

    @Autowired
    private RedissonLockUtil redissonLockUtil;

    @Autowired
    private RedissonClient redissonClient;

    public RedisKeyExpiredListener(RedisMessageListenerContainer listenerContainer) {
        super(listenerContainer);
    }

    @Override
    public void onMessage(Message message, byte[] pattern) {
        String expiredKey = message.toString();
        if (expiredKey.startsWith(RedisKeyPrefix.AUTO_CHECKIN_PREFIX)) {
            redissonLockUtil.execute("LOCK:"+expiredKey, CommonConstant.DEFAULT_0, CommonConstant.DEFAULT_10, () -> {
                // 执行业务逻辑
                String idStr = expiredKey.replace(RedisKeyPrefix.AUTO_CHECKIN_PREFIX, "");
                try {
                    //模拟签到完成
                    Long registerId = Long.valueOf(idStr);
                    // 再来一层SETNX幂等，防止各种鬼情况
                    String claimKey = "claim:clinic:auto_checkin:" + registerId;
                    Boolean ok = redissonClient.getBucket(claimKey).trySet("1", 120, TimeUnit.SECONDS);
                    if (Boolean.FALSE.equals(ok)) {
                        return;
                    }
                    log.info(">>>>>>>>>>>>>>>>>>>>>>>>>>开始执行自动签到的逻辑>>>>>>>>>>>>>>>>>>>>>>>>>>");
                    ClinicRegister dbClinicRegister = registerService.getRegisterById(registerId);
                    if(dbClinicRegister == null){
                        return;
                    }
                    //1.回写挂号单状态
                    registerService.checkIn(dbClinicRegister);
                    //2.加入到排队表
                    checkinService.checkInAndEnqueue(dbClinicRegister);
                    //3.添加门诊数据
                    clinicMedicalService.checkInAndMedical(dbClinicRegister);
                    log.info(">>>>>>>>>>>>>>>>>>>>>>>>>>结束执行自动签到的逻辑>>>>>>>>>>>>>>>>>>>>>>>>>>");
                } catch (Exception e) {
                    log.error("解析签到ID失败",e);
                }
            });
        }
    }
}

